#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <pthread.h>
#include <sys/types.h>
#include <limits.h> 
#include <errno.h>
#include <unistd.h>

//#include <unistd.h>
#define LOOPS 4
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; 
pthread_mutex_t mutex_i = PTHREAD_MUTEX_INITIALIZER; 
pthread_mutex_t mutex_j = PTHREAD_MUTEX_INITIALIZER; 
#define number_of_threads1 4
#define number_of_threads2 8

int a=1;
int postep1=0;
int postep2=0;
int pasek1=0;
int pasek2=0;
float procent1=0;
float procent2=0;
int id_watku;
int start,stop;
unsigned int non_zeros;	//LICZBA NIEZEROWYCH ELEMENTÓW
unsigned int rowsPLUS1;	//ROZMIAR WEKTORA Z INDEKSAMI POCZĄTKÓW WIERSZY
int dlugosc;
WINDOW *my_win;
FILE *plik;

WINDOW *create_newwin(int height, int width, int starty, int startx);
void destroy_win(WINDOW *local_win);


typedef struct _Arg{
unsigned int number_of_rows;
unsigned int number_of_non_zeros;
double *non_zeros;
int *row_pointer;
int *column_index;
double *source_vector;
double *destination_vector;
int row_start;
int row_stop;
int number_of_threads;
int pozycja;
int suma;
}Argument;

void *smvm_for(void *p)
{
	Argument* param= (Argument*)(p);
	
	for(param->pozycja=param->row_start;param->pozycja<=param->row_stop; ){
		postep2=param->pozycja;
		pthread_mutex_lock( &mutex_i );
		param->suma++;
		id_watku=pthread_self();
		//printf("\n\rwatek: %d, i: %d",id_watku,param->pozycja );
        	start=param->row_start;
        	stop=param->row_stop;
        	param->pozycja++;
		pthread_mutex_unlock( &mutex_i );
		
		for ( int j = param->row_pointer[param->pozycja]; j < param->row_pointer[param->pozycja+1]; j++ ){
		//pthread_mutex_lock( &mutex1 );
		param->destination_vector[param->pozycja] += param->non_zeros[j]*param->source_vector[param->column_index[j]];
		//   postep2++;
		//    pthread_mutex_unlock( &mutex1 );
        	}
        	usleep(5000);
        	
	}
       	pthread_exit(NULL);
       return 0;
}

//Mnozenie z uzyciem watkow

void *smvm_threads(void *pa)
{	
	Argument* arg= (Argument*)(pa);
	Argument temp;
	temp=*arg;
	int dlugosc = (int)((arg->number_of_non_zeros/arg->number_of_threads)+0.5);
	pthread_t *threads= new pthread_t[arg->number_of_threads];
	for(int i=0;i<=arg->number_of_threads; i++){
		
		temp.row_start=dlugosc*i;
		if(i==arg->number_of_threads-1){
		temp.row_stop=temp.number_of_non_zeros;
		}
		else{
		temp.row_stop=dlugosc*(i+1);
		}
		//pthread_create(&threads[i], NULL, smvm_for, (void*)&temp);
		//postep2++;
		usleep(4000);
	}
	return 0;
}
///mnożenie std.
void smvm ( int *row_ptr, int* col_idx, double* value,double* x,double* y, int m) 
{  for ( int i=0; i <= m; i++ ){
        y[i] = 0;
        for ( int j = row_ptr[i]; j < row_ptr[i+1]; j++ ){
            y[i] += value[j]*x[col_idx[j]];
        }
    }
}


void* paski(void* _arg) {    
  
			procent2=(float)arg[0].suma/(float)dlugosc*100;
   			pasek2=(procent2*(width-4))/100;
   			//move(17,4); attron(A_BOLD);
      			//wprintw(stdscr, "Watek 2:");  
			move(18,4); attron(A_BOLD);
      			wprintw(stdscr, "Postep:   %0.2f procent",procent2); 
   			
   			
   			
			move(20,pasek2+3); attron(A_BOLD);   //-100%
								
      			wprintw(stdscr, "|");
			refresh();
			usleep(100);		
		

 return NULL;
}

void* watek2(void* _arg) {      

	
	sleep(1);
 return NULL;
}
void init_wynik(double *w, int liczbaKolumn)
{
		for(int k=0;k<liczbaKolumn;k++)
		{
			w[k]=0;
		}
}


int main(){
  
int y;
int ch;
	int liczbaElementow=1;
	int liczbaWierszy=1;
	int liczbaKolumn=1;
	int tmp,tmp2;

int startx, starty, width, height;
int i, j,r,s=0;
char str[80];

	initscr();
	pthread_t id1;
	pthread_t id2;
        Argument arg1,arg2;
        Argument *arg;
 
      
             
		
           //  errno = pthread_create(&id2, NULL, watek2, NULL);     
    		//test_errno("Nie powiodło się pthread_create");     
		//test_errno("Nie powiodło się pthread_create");
	


	raw();
	keypad(stdscr, TRUE);           //We get F1, F2 etc..         
                            
        height = LINES;
        width = COLS;
        starty = 0; // Calculating for a center placement
        startx = 0;  
	printw("Press F1 to exit");
	
        refresh();
        my_win = create_newwin(height, width, starty, startx);
	move(2,4); attron(A_BOLD);
        wprintw(stdscr, "Mnozenie macierzy przez wektor"); 
	move(3,4); attron(A_BOLD);
        wprintw(stdscr, "pthreads/ncurses");  
	
	for (j=2;j<5;j++)
	for (i=COLS-25;i<COLS-22;i++){
	move(j,i); attron(A_BOLD|A_BLINK);
        wprintw(stdscr, "#");  }
	move(3,COLS-21); attron(A_BOLD|A_BLINK);
        wprintw(stdscr, "o");
	for (j=2;j<5;j++){
	move(j,COLS-19); attron(A_BOLD|A_BLINK);
        wprintw(stdscr, "#");  }

	my_win = create_newwin(height-7, width-2, 6, startx+1);

			move(8,4); attron(A_BOLD);
      			wprintw(stdscr, "Podaj nazwe macierzy:");  
 			getstr(str);
			move(8,45); attron(A_BOLD);
      			wprintw(stdscr, str);  
			move(10,4); attron(A_BOLD);
      			wprintw(stdscr, "Watek 1:");  
			move(11,4); attron(A_BOLD);
      			wprintw(stdscr, "Postep:   0 procent"); 
			my_win = create_newwin(3, width-4, 12, startx+2);
				r=8;
			move(9+r,4); attron(A_BOLD);
      			wprintw(stdscr, "Watek 2:");  
			move(10+r,4); attron(A_BOLD);
      			wprintw(stdscr, "Postep:   0 procent"); 
			my_win = create_newwin(3, width-4, 11+r, startx+2);

		//////////////WCZYTANIE PLIKU
			//plik=fopen(str, "rb" );
				if  ((plik=fopen("raefskyCSR.txt", "r"))==NULL)
				{
			 	printf("Nie moge otworzyc pliku!\n");   
				}
				fscanf(plik, "%d %d", &liczbaWierszy,&liczbaElementow);
	
				liczbaKolumn=liczbaWierszy;
				//printf("\n%d %d %d", liczbaWierszy,liczbaKolumn,liczbaElementow);

				int *col=new int[liczbaElementow];
				//int *col_mkl=new int[liczbaElementow];
				int *row_ptr=new int[liczbaWierszy+1];
				//int *row_ptr_mkl=new int[liczbaWierszy+1];
				double *val=new double[liczbaElementow];
	

				while (feof(plik)==0 && s<liczbaElementow)
				{
				fscanf(plik, "%d %d %lf", &tmp,&tmp2,&val[s]);
					col[s]=tmp2-1;			//dla MKL -1
					//col_mkl[i]=tmp2;	
					if (s<liczbaWierszy+1)
					{ row_ptr[s]=tmp-1;		//-1
					  //row_ptr_mkl[i]=tmp;
					}
				       s++;
				}
				if  (fclose(plik))
				{
					printf("Nie moge zamknac pliku!\n");
				}

				//for(j=0;j<10;j++){
				//	printf("\n%d %d %.10lf", row_ptr[j],col[j],val[j]);
				//}
	

				double *vec=new double[liczbaKolumn];
				double *wynik_watek=new double[liczbaKolumn];
				double *wynik_std=new double[liczbaKolumn];
			    	
			   	for(int k=0;k<liczbaKolumn;k++)
				{
					vec[k]=1;		//(float)999999/(float)1000000;	//rand()%100000 +1;  
					wynik_std[k]=0;
					wynik_watek[k]=0;
					
				}	
				
				
				arg=new Argument[number_of_threads1];
				pthread_t *threads= new pthread_t[number_of_threads1];
				
				 dlugosc = (int)(((float)liczbaWierszy/(float)number_of_threads1)+0.5);
				
				smvm(row_ptr, col, val, vec, wynik_std, liczbaKolumn-1);
				//smvm(row_ptr, col, val, vec, wynik_watek, liczbaKolumn);
				 arg[0].number_of_rows=liczbaWierszy;
				 arg[0].number_of_non_zeros=liczbaElementow;
				 arg[0].non_zeros=val;
				 arg[0].row_pointer=row_ptr;
				 arg[0].column_index=col;
				 arg[0].source_vector=vec;
				 arg[0].destination_vector=wynik_watek;
				 arg[0].row_start=0;
				 arg[0].row_stop=dlugosc;
				 arg[0].pozycja=0;

				for(int i=0;i<number_of_threads1; i++){
					
					arg[i]=arg[0];
					arg[i].row_start=dlugosc*i;
					//arg[i].row_stop=dlugosc*(i+1);
					if(i==(number_of_threads1-1)){
					arg[i].row_stop=liczbaWierszy-1;
					}
					else{
					arg[i].row_stop=dlugosc*(i+1);
					}
					pthread_create(&threads[i], NULL, smvm_for, (void*)&arg[i]);
			 	printf( "\n\rrow_start: %d, row_stop: %d,dlug: %d",arg[i].row_start,arg[i].row_stop,arg[i].row_stop-arg[i].row_start); 
				}	
				
				
				pthread_create(id1, NULL, paski, NULL);
				 	


	//////
	
				
			while(procent2<=100){
			//move(10+r,4); attron(A_BOLD);
  	  		//printf( "\n\rwatek_pid: %d , i: %d, row_start: %d, row_stop: %d,dlug: %d",id_watku,postep2,start,stop,dlugosc); 
   			//printf( "\n\rSuma1: %d, Suma2: %d",arg[0].suma, arg[1].suma);
   			procent2=(float)arg[0].suma/(float)dlugosc*100;
   			pasek2=(procent2*(width-4))/100;
   			//move(17,4); attron(A_BOLD);
      			//wprintw(stdscr, "Watek 2:");  
			move(18,4); attron(A_BOLD);
      			wprintw(stdscr, "Postep:   %0.2f procent",procent2); 
   			
   			
   			
			move(20,pasek2+3); attron(A_BOLD);   //-100%
								
      			wprintw(stdscr, "|");
			refresh();
			//usleep(100);			
			}
			//pthread_join(*threads, NULL);	
				for (int i=0;i<liczbaKolumn;i++){
				if(wynik_std[i]!=wynik_watek[i])
				printf("\n\rBlad, %f.9 %f.9",wynik_std[i],wynik_watek[i] );
				printf("\n\ri: %d, wynik watek: %f wyniki std: %f",i ,wynik_watek[i],wynik_std[i]);
				}
				printf("Sukces");
			

        getch();     
	endwin();
	//errno = pthread_join(id1, NULL); 
             
//errno = pthread_join(id2, NULL);

return 0;
};
WINDOW *create_newwin(int height, int width, int starty, int startx)
{       WINDOW *local_win;

        local_win = newwin(height, width, starty, startx);
        box(local_win, 0 , 0);        
        
 
        wrefresh(local_win);           
        return local_win;
}




